/*
 * analyser.cc
 *
 *  Created on: Dec 6, 2012
 *      Author: hxin
 */

#include "analyser.h"
#include "twoLvHTAnalyser.h"
#include "common.h"
#include <cmath>
#include <cassert>
#include <fstream>

analyser::analyser() {
	ht = new refAnalyser();
}

analyser::analyser(string refFileName, int KmerSize, int maxError) {
	switch (analyser_config) {
	case FAKE_ALIGN_BASE:
		ht = new refAnalyser(refFileName, KmerSize, maxError);
		break;
	case FAKE_ALIGN_2LV:
		ht = new twoLvHTAnalyser(refFileName, KmerSize, maxError);
		this->KmerSize = KmerSize * 2;
		break;
	case FAKE_ALIGN_HET:
		ht = new hashGen(refFileName, "testHT.index" , KmerSize, maxError);
		break;
	}
	this->KmerSize = KmerSize;

	refFile.open(refFileName.c_str());
}

analyser::analyser(string refFileName, int shortHTLength, int midHTLength,
		int longHTLength, int lvThreshold) {
	ht = new twoLvHTAnalyser(refFileName, shortHTLength, midHTLength,
			longHTLength, 5, lvThreshold);
	this->KmerSize = midHTLength;
	refFile.open(refFileName.c_str());
}

analyser::analyser(const analyser & rhs) {
	ht = rhs.ht->clone();
	KmerFreq.resize(rhs.KmerFreq.size());
	for (int i = 0; i < KmerFreq.size(); i++)
		KmerFreq[i] = rhs.KmerFreq[i];
	for (int i = 0; i < BUFFSIZE; i++)
		ppmBuff[i] = rhs.ppmBuff[i];
	KmerSize = rhs.KmerSize;
	refFile.open(rhs.refFileName.c_str());
}

analyser& analyser::operator =(const analyser & rhs) {
	delete ht;
	ht = rhs.ht->clone();
	KmerFreq.resize(rhs.KmerFreq.size());
	for (int i = 0; i < KmerFreq.size(); i++)
		KmerFreq[i] = rhs.KmerFreq[i];
	for (int i = 0; i < BUFFSIZE; i++)
		ppmBuff[i] = rhs.ppmBuff[i];
	KmerSize = rhs.KmerSize;
	refFile.open(rhs.refFileName.c_str());

	return *this;
}

analyser::~analyser() {
	delete ht;
	refFile.close();
	//ht.~refAnalyser();
}

void analyser::sweepChromosome(int chrNum) {
	ht->loadHash(chrNum);

	int chrSize = countChr(chrNum);
	int progressCount = 0;

	cerr << "chrSize: " << chrSize << endl;

	KmerFreq.resize(chrSize, 0);
	gotoChr(chrNum);

	char tempChar;
	string tempKey;

	int skipN = 0;

	//get first Kmer
	for (int i = 0; i < KmerSize; i++) {

		refFile >> tempChar;
		//show progress
		makeProgress("AnalyseHash", progressCount, chrSize, 100000);

		if (tempChar == 'N' || tempChar == 'M' || tempChar == 'R') {
			skipN = KmerSize;
		}
		tempKey += tempChar;
	}

	while (refFile.good() && tempChar != '>') {

		//If there is any N, we skip the Kmer
		if (tempChar == 'N' || tempChar == 'M' || tempChar == 'R') {
			skipN = KmerSize;
		}

		if (skipN == 0) {
			assert(progressCount < chrSize);
			if (analyser_config == FAKE_ALIGN_2LV)
				KmerFreq[progressCount] = ((twoLvHTAnalyser*) ht)->testLv(tempKey).size();
			else
				KmerFreq[progressCount] = ht->query(tempKey).size();
			assert(KmerFreq[progressCount] > 0);
		} else {
			skipN--;
		}

		refFile >> tempChar;
		//show progress
		makeProgress("AnalyseHash", progressCount, chrSize, 100000);

		tempKey = tempKey.substr(1, KmerSize - 1) + tempChar;
	}

	assert(progressCount == chrSize);
}

void analyser::sweepChromosome(int chrNum, int readLength) {
	ht->loadHash(chrNum);

	int chrSize = countChr(chrNum);
	int progressCount = 0;

	cerr << "chrSize: " << chrSize << endl;

	KmerFreq.resize(chrSize, 0);
	gotoChr(chrNum);

	char tempChar;
	string tempRead;

	int skipN = 0;

	//get first Kmer
	for (int i = 0; i < readLength; i++) {

		refFile >> tempChar;
		//show progress
		makeProgress("SweepingChromosome", progressCount, chrSize, 1000);

		if (tempChar == 'N' || tempChar == 'M' || tempChar == 'R') {
			skipN = readLength;
		}
		tempRead += tempChar;
	}

	while (refFile.good() && tempChar != '>') {

		//cerr << "Why not in this?" << endl;

		//If there is any N, we skip the Kmer
		if (tempChar == 'N' || tempChar == 'M' || tempChar == 'R') {
			skipN = readLength;
		}

		if (skipN == 0) {
			assert(progressCount < chrSize);

			cerr << "Read[" << progressCount << "]: " << tempRead << endl;

			if (analyser_config == FAKE_ALIGN_2LV)
				KmerFreq[progressCount] = ((twoLvHTAnalyser*) ht)->testLv(tempRead).size();
			else
				KmerFreq[progressCount] = ht->query(tempRead).size();

//			cout << "read: " << tempRead << endl;
//			cout << "KmerFreq[" << progressCount<< "]: " << KmerFreq[progressCount] << endl;
			assert(KmerFreq[progressCount] > 0);
		} else {
			skipN--;
		}

		refFile >> tempChar;
		//show progress
		makeProgress("SweepingChromosome", progressCount, chrSize, 1000);

		tempRead = tempRead.substr(1, readLength - 1) + tempChar;
	}

	assert(progressCount == chrSize);
}

void analyser::unloadHash() {
	KmerFreq.clear();
	refAnalyser::unloadHash();
	ht->unloadHash();
}

unsigned long int analyser::genStat(unsigned long int prevUnitColor) {
	//ht->genStat();

	for (int i = 0; i < BUFFSIZE; i++)
		ppmBuff[i] = 0;

	unsigned long int maxBuffColor = 0;
	int unitSize = KmerFreq.size() / BUFFSIZE + 1;
	unsigned long int cumulatedColor = 0;
	unsigned int buffCount = 0;
	unsigned int statCount = 0;
	totalFreq = 0;
	//cout << "KmerFreq.size()" << KmerFreq.size() << endl;
	while (statCount < KmerFreq.size()) {
		for (int i = 0; i < unitSize && statCount < KmerFreq.size(); i++) {
			cumulatedColor += KmerFreq[statCount];
			totalFreq += KmerFreq[statCount];
			makeProgress("Generating Color", statCount,
					(unsigned int) KmerFreq.size(), (unsigned int)BUFFSIZE);
		}
		if (cumulatedColor > maxBuffColor)
			maxBuffColor = cumulatedColor;

		ppmBuff[buffCount] = cumulatedColor;
		buffCount++;
		cumulatedColor = 0;

		/*
		 if (KmerFreq[statCount] != 0)
		 KmerFreq[statCount] = (int) log(KmerFreq[statCount]) + 1;
		 if (KmerFreq[statCount] > maxBuffColor)
		 maxBuffColor = KmerFreq[statCount];
		 makeProgress("Generating Color", statCount,
		 (unsigned int) KmerFreq.size(), 100000);
		 */
	}

	//cout << "buffCount: " << buffCount << endl;
	//assert(buffCount == 1000000);
	//maxBuffColor = maxBuffColor / 255 + 1;

	if (maxBuffColor < prevUnitColor)
		maxBuffColor = prevUnitColor;

	for (buffCount = 0; buffCount < BUFFSIZE; buffCount++) {
		//cout << "ppmBuff[" << buffCount << "] = " << ppmBuff[buffCount] << endl;
		ppmBuff[buffCount] = (int) log(ppmBuff[buffCount] + 1);
		//cout << "new ppmBuff[" << buffCount << "] = " << ppmBuff[buffCount]
		//		<< endl;
	}

	return maxBuffColor;
}

void analyser::printStat() {
	ht->printStat();
	cout << "Total frequency of the chromosome: " << totalFreq << endl;
	cout << "Chromosome length: " << KmerFreq.size() << endl;
	cout << "Average frequency of the chromosome: "
			<< totalFreq / KmerFreq.size() << endl;
}

void analyser::printPic(string picName, unsigned long int maxUnitColor) {
	ofstream picFile;
	picFile.open(picName.c_str());
	picFile << "P3" << endl;
	picFile << BUFFSIZE << ' ' << 10 << endl;
	int fullColor = (int) log(maxUnitColor + 1) + 1;
	picFile << fullColor << endl;
	for (int i = 0; i < 10; i++) {
		unsigned int printCount = 0;
		while (printCount < BUFFSIZE) {
			picFile << ppmBuff[printCount] << ' '
					<< fullColor - ppmBuff[printCount] << ' ' << 0 << '\t';
			makeProgress("PrintingPic", printCount, (unsigned int) BUFFSIZE,
					(unsigned int)100000);
		}
		picFile << endl;
	}
	picFile.close();
}
